/*
 */
package org.hook.showcase.concurrent.tools;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author suwuqiang 2011-12-16
 */
public class CyclicBarrierCase {
	private final CyclicBarrier barrier;
	private final AtomicInteger counter;
	private final int total;

	public CyclicBarrierCase(final int total, final int limit) {
		this.total = total;
		this.counter = new AtomicInteger(total);
		this.barrier = new CyclicBarrier(limit);
	}

	public void execute(final Runnable task) {
		final int total = this.total;
		new Thread() {
			public void run() {
				try {
					barrier.await();
					synchronized (counter) {
						task.run();
						int value = counter.decrementAndGet();
						if (value % barrier.getParties() == 0) {
							float percent = (float) (total - value) / total;
							System.out.println(percent * 100 + "% done.");
						}
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					e.printStackTrace();
				}
			};
		}.start();
	}

	private static class DoPrintTask extends Thread {
		private final int taskId;

		public DoPrintTask(final int value) {
			this.taskId = value;
		}

		@Override
		public void run() {
			System.out.println("Task[" + String.format("%03d", this.taskId) + "] is done.");
		}
	}

	public static void main(String[] args) {
		final int TASK_MAX_SIZE = 40;
		final int TASK_BATCH_SIZE = 10;
		CyclicBarrierCase worker = new CyclicBarrierCase(TASK_MAX_SIZE, TASK_BATCH_SIZE);
		for (int i = 0; i < TASK_MAX_SIZE; i++) {
			int index = i + 1;
			DoPrintTask task = new DoPrintTask(index);
			worker.execute(task);
		}
	}
}
